home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / X11 / XLOADIMG.TAR / send.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  17KB  |  629 lines

  1. /* send.c:
  2.  *
  3.  * send an Image to an X pixmap
  4.  *
  5.  * jim frost 10.02.89
  6.  *
  7.  * Copyright 1989, 1990, 1991 Jim Frost.
  8.  * See included file "copyright.h" for complete copyright information.
  9.  */
  10.  
  11. #include "copyright.h"
  12. #include "xloadimage.h"
  13.  
  14. static int GotError;
  15.  
  16. static int pixmapErrorTrap(disp, pErrorEvent)
  17.     Display    *disp;
  18.     XErrorEvent * pErrorEvent;
  19. {
  20. #define MAXERRORLEN 100
  21.     char buf[MAXERRORLEN+1];
  22.     GotError = 1;
  23.     XGetErrorText(disp, pErrorEvent->error_code, buf, MAXERRORLEN);
  24.     printf("serial #%d (request code %d) Got Error %s\n",
  25.     pErrorEvent->serial,
  26.     pErrorEvent->request_code,
  27.     buf);
  28.     return(0);
  29. }
  30.  
  31. Pixmap ximageToPixmap(disp, parent, ximageinfo)
  32.      Display    *disp;
  33.      Window      parent;
  34.      XImageInfo *ximageinfo;
  35. {
  36.   int         (*old_handler)();
  37.   Pixmap        pixmap;
  38.  
  39.   GotError = 0;
  40.   old_handler = XSetErrorHandler(pixmapErrorTrap);
  41.   XSync(disp, False);
  42.   pixmap= XCreatePixmap(disp, parent,
  43.             ximageinfo->ximage->width, ximageinfo->ximage->height,
  44.             ximageinfo->depth);
  45.   (void)XSetErrorHandler(old_handler);
  46.   if (GotError)
  47.     return(None);
  48.   ximageinfo->drawable= pixmap;
  49.   sendXImage(ximageinfo, 0, 0, 0, 0,
  50.          ximageinfo->ximage->width, ximageinfo->ximage->height);
  51.   return(pixmap);
  52. }
  53.  
  54. /* find the best pixmap depth supported by the server for a particular
  55.  * visual and return that depth.
  56.  *
  57.  * this is complicated by R3's lack of XListPixmapFormats so we fake it
  58.  * by looking at the structure ourselves.
  59.  */
  60.  
  61. static unsigned int bitsPerPixelAtDepth(disp, scrn, depth)
  62.      Display      *disp;
  63.      int           scrn;
  64.      unsigned int  depth;
  65. {
  66. #if 1 /* the way things are */
  67.   unsigned int a;
  68.  
  69.   for (a= 0; a < disp->nformats; a++)
  70.     if (disp->pixmap_format[a].depth == depth)
  71.       return(disp->pixmap_format[a].bits_per_pixel);
  72.  
  73. #else /* the way things should be */
  74.   XPixmapFormatValues *xf;
  75.   unsigned int nxf, a;
  76.  
  77.   xf = XListPixmapFormats(disp, &nxf);
  78.   for (a = 0; a < nxf; a++)
  79.     if (xf[a].depth == closest_depth)
  80.       return(disp->pixmap_format[a].bits_per_pixel);
  81. #endif
  82.  
  83.   /* this should never happen; if it does, we're in trouble
  84.    */
  85.  
  86.   fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
  87.   exit(1);
  88. }
  89.      
  90. XImageInfo *imageToXImage(disp, scrn, visual, ddepth, image, private_cmap, fit,
  91.               verbose)
  92.      Display      *disp;
  93.      int           scrn;
  94.      Visual       *visual; /* visual to use */
  95.      unsigned int  ddepth; /* depth of the visual to use */
  96.      Image        *image;
  97.      unsigned int  private_cmap;
  98.      unsigned int  fit;
  99.      unsigned int  verbose;
  100. { Pixel        *index, *redvalue, *greenvalue, *bluevalue;
  101.   unsigned int  a, b, newmap, x, y, linelen, dpixlen, dbits;
  102.   XColor        xcolor;
  103.   XGCValues     gcv;
  104.   XImageInfo   *ximageinfo;
  105.   Image        *orig_image;
  106.  
  107.   goodImage(image, "imageToXimage");
  108.  
  109.   xcolor.flags= DoRed | DoGreen | DoBlue;
  110.   index= redvalue= greenvalue= bluevalue= NULL;
  111.   orig_image= image;
  112.   ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
  113.   ximageinfo->disp= disp;
  114.   ximageinfo->scrn= scrn;
  115.   ximageinfo->depth= 0;
  116.   ximageinfo->drawable= None;
  117.   ximageinfo->foreground= ximageinfo->background= 0;
  118.   ximageinfo->gc= NULL;
  119.   ximageinfo->ximage= NULL;
  120.  
  121.   /* process image based on type of visual we're sending to
  122.    */
  123.  
  124.   switch (image->type) {
  125.   case ITRUE:
  126.     switch (visual->class) {
  127.     case TrueColor:
  128.     case DirectColor:
  129.       /* goody goody */
  130.       break;
  131.     default:
  132.       if (visual->bits_per_rgb > 1)
  133.     image= reduce(image, depthToColors(visual->bits_per_rgb), verbose);
  134.       else
  135.     image= dither(image, verbose);
  136.     }
  137.     break;
  138.  
  139.   case IRGB:
  140.     switch(visual->class) {
  141.     case TrueColor:
  142.     case DirectColor:
  143.       /* no problem, we handle this just fine */
  144.       break;
  145.     default:
  146.       if (visual->bits_per_rgb < 2)
  147.     image= dither(image, verbose);
  148.       break;
  149.     }
  150.  
  151.   case IBITMAP:
  152.     /* no processing ever needs to be done for bitmaps */
  153.     break;
  154.   }
  155.  
  156.   /* do color allocation
  157.    */
  158.  
  159.   switch (visual->class) {
  160.   case TrueColor:
  161.   case DirectColor:
  162.     { Pixel pixval;
  163.       unsigned int redcolors, greencolors, bluecolors;
  164.       unsigned int redstep, greenstep, bluestep;
  165.       unsigned int redbottom, greenbottom, bluebottom;
  166.       unsigned int redtop, greentop, bluetop;
  167.  
  168.       redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  169.       greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  170.       bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  171.  
  172.       if (visual == DefaultVisual(disp, scrn))
  173.     ximageinfo->cmap= DefaultColormap(disp, scrn);
  174.       else
  175.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  176.                       visual, AllocNone);
  177.  
  178.       retry_direct: /* tag we hit if a DirectColor allocation fails on
  179.              * default colormap */
  180.  
  181.       /* calculate number of distinct colors in each band
  182.        */
  183.  
  184.       redcolors= greencolors= bluecolors= 1;
  185.       for (pixval= 1; pixval; pixval <<= 1) {
  186.     if (pixval & visual->red_mask)
  187.       redcolors <<= 1;
  188.     if (pixval & visual->green_mask)
  189.       greencolors <<= 1;
  190.     if (pixval & visual->blue_mask)
  191.       bluecolors <<= 1;
  192.       }
  193.       
  194.       /* sanity check
  195.        */
  196.  
  197.       if ((redcolors > visual->map_entries) ||
  198.       (greencolors > visual->map_entries) ||
  199.       (bluecolors > visual->map_entries)) {
  200.     fprintf(stderr, "\
  201. Warning: inconsistency in color information (this may be ugly)\n");
  202.       }
  203.  
  204.       redstep= 256 / redcolors;
  205.       greenstep= 256 / greencolors;
  206.       bluestep= 256 / bluecolors;
  207.       redbottom= greenbottom= bluebottom= 0;
  208.       for (a= 0; a < visual->map_entries; a++) {
  209.     if (redbottom < 256)
  210.       redtop= redbottom + redstep;
  211.     if (greenbottom < 256)
  212.       greentop= greenbottom + greenstep;
  213.     if (bluebottom < 256)
  214.       bluetop= bluebottom + bluestep;
  215.  
  216.     xcolor.red= (redtop - 1) << 8;
  217.     xcolor.green= (greentop - 1) << 8;
  218.     xcolor.blue= (bluetop - 1) << 8;
  219.     if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
  220.  
  221.       /* if an allocation fails for a DirectColor default visual then
  222.        * we should create a private colormap and try again.
  223.        */
  224.  
  225.       if ((visual->class == DirectColor) &&
  226.           (visual == DefaultVisual(disp, scrn))) {
  227.         ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  228.                           visual, AllocNone);
  229.         goto retry_direct;
  230.       }
  231.  
  232.       /* something completely unexpected happened
  233.        */
  234.  
  235.       fprintf(stderr, "\
  236. imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
  237.       return(NULL);
  238.     }
  239.  
  240.     /* fill in pixel values for each band at this intensity
  241.      */
  242.  
  243.     while ((redbottom < 256) && (redbottom < redtop))
  244.       redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
  245.     while ((greenbottom < 256) && (greenbottom < greentop))
  246.       greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
  247.     while ((bluebottom < 256) && (bluebottom < bluetop))
  248.       bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
  249.       }
  250.     }
  251.     break;
  252.  
  253.   default:
  254.   retry: /* this tag is used when retrying because we couldn't get a fit */
  255.     index= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
  256.  
  257.     /* private_cmap flag is invalid if not a dynamic visual
  258.      */
  259.  
  260.     switch (visual->class) {
  261.     case StaticColor:
  262.     case StaticGray:
  263.       private_cmap= 0;
  264.     }
  265.  
  266.     /* get the colormap to use.
  267.      */
  268.  
  269.     if (private_cmap) { /* user asked us to use a private cmap */
  270.       newmap= 1;
  271.       fit= 0;
  272.     }
  273.     else if ((visual == DefaultVisual(disp, scrn)) ||
  274.          (visual->class == StaticGray) ||
  275.          (visual->class == StaticColor)) {
  276.  
  277.       /* if we're using the default visual, try to alloc colors shareable.
  278.        * otherwise we're using a static visual and should treat it
  279.        * accordingly.
  280.        */
  281.  
  282.       if (visual == DefaultVisual(disp, scrn))
  283.     ximageinfo->cmap= DefaultColormap(disp, scrn);
  284.       else
  285.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  286.                       visual, AllocNone);
  287.       newmap= 0;
  288.  
  289.       /* allocate colors shareable (if we can)
  290.        */
  291.  
  292.       for (a= 0; a < image->rgb.used; a++) {
  293.     xcolor.red= *(image->rgb.red + a);
  294.     xcolor.green= *(image->rgb.green + a);
  295.     xcolor.blue= *(image->rgb.blue + a);
  296.     if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
  297.       if ((visual->class == StaticColor) ||
  298.           (visual->class == StaticGray)) {
  299.         printf("imageToXImage: XAllocColor failed on a static visual\n");
  300.         return(NULL);
  301.       }
  302.       else {
  303.  
  304.         /* we can't allocate the colors shareable so free all the colors
  305.          * we had allocated and create a private colormap (or fit
  306.          * into the default cmap if `fit' is true).
  307.          */
  308.  
  309.         XFreeColors(disp, ximageinfo->cmap, index, a, 0);
  310.         newmap= 1;
  311.         break;
  312.       }
  313.     *(index + a)= xcolor.pixel;
  314.       }
  315.     }
  316.     else {
  317.       newmap= 1;
  318.       fit= 0;
  319.     }
  320.  
  321.     if (newmap) {
  322.  
  323.       /* either create a new colormap or fit the image into the one we
  324.        * have.  to create a new one, we create a private cmap and allocate
  325.        * the colors writable.  fitting the colors is harder, we have to:
  326.        *  1. grab the server so no one can goof with the colormap.
  327.        *  2. count the available colors using XAllocColorCells.
  328.        *  3. free the colors we just allocated.
  329.        *  4. reduce the depth of the image to fit.
  330.        *  5. allocate the colors again shareable.
  331.        *  6. ungrab the server and continue on our way.
  332.        * someone should shoot the people who designed X color allocation.
  333.        */
  334.  
  335.       if (fit) {
  336.     if (verbose)
  337.       printf("  Fitting image into default colormap\n");
  338.     XGrabServer(disp);
  339.       }
  340.       else {
  341.     if (verbose)
  342.       printf("  Using private colormap\n");
  343.  
  344.     /* create new colormap
  345.      */
  346.  
  347.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  348.                       visual, AllocNone);
  349.       }
  350.  
  351.       for (a= 0; a < image->rgb.used; a++) /* count entries we got */
  352.     if (! XAllocColorCells(disp, ximageinfo->cmap, False, NULL, 0,
  353.                    index + a, 1))
  354.       break;
  355.  
  356.       if (fit) {
  357.     if (a > 0)
  358.       XFreeColors(disp, ximageinfo->cmap, index, a, 0);
  359.     if (a <= 2) {
  360.       if (verbose) {
  361.         printf("  Cannot fit into default colormap, dithering...");
  362.         fflush(stdout);
  363.       }
  364.       image= dither(image, 0);
  365.       if (verbose)
  366.         printf("done\n");
  367.       fit= 0;
  368.       lfree(index);
  369.       goto retry;
  370.     }
  371.       }
  372.  
  373.       if (a == 0) {
  374.     fprintf(stderr, "imageToXImage: Color allocation failed!\n");
  375.     lfree(index);
  376.     return(NULL);
  377.       }
  378.  
  379.       if (a < image->rgb.used)
  380.     image= reduce(image, a, verbose);
  381.  
  382.       if (fit) {
  383.     for (a= 0; a < image->rgb.used; a++) {
  384.       xcolor.red= *(image->rgb.red + a);
  385.       xcolor.green= *(image->rgb.green + a);
  386.       xcolor.blue= *(image->rgb.blue + a);
  387.  
  388.       /* if this fails we're in trouble
  389.        */
  390.  
  391.       if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
  392.         printf("XAllocColor failed while fitting colormap!\n");
  393.         return(NULL);
  394.       }
  395.       *(index + a)= xcolor.pixel;
  396.     }
  397.     XUngrabServer(disp);
  398.       }
  399.       else {
  400.     for (b= 0; b < a; b++) {
  401.       xcolor.pixel= *(index + b);
  402.       xcolor.red= *(image->rgb.red + b);
  403.       xcolor.green= *(image->rgb.green + b);
  404.       xcolor.blue= *(image->rgb.blue + b);
  405.       XStoreColor(disp, ximageinfo->cmap, &xcolor);
  406.     }
  407.       }
  408.     }
  409.     break;
  410.   }
  411.  
  412.   /* create an XImage and related colormap based on the image type
  413.    * we have.
  414.    */
  415.  
  416.   if (verbose) {
  417.     printf("  Building XImage...");
  418.     fflush(stdout);
  419.   }
  420.  
  421.   switch (image->type) {
  422.   case IBITMAP:
  423.     { byte *data;
  424.  
  425.       /* we copy the data to be more consistent
  426.        */
  427.  
  428.       data= lmalloc((image->width + 7) / 8 * image->height);
  429.       bcopy(image->data, data, ((image->width + 7) / 8) * image->height);
  430.  
  431.       gcv.function= GXcopy;
  432.       ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
  433.                        0, data, image->width, image->height,
  434.                        8, 0);
  435.       ximageinfo->depth= ddepth;
  436.       ximageinfo->foreground= *(index + 1);
  437.       ximageinfo->background= *index;
  438.       ximageinfo->ximage->bitmap_bit_order= MSBFirst;
  439.       ximageinfo->ximage->byte_order= MSBFirst;
  440.       break;
  441.     }
  442.  
  443.   case IRGB:
  444.   case ITRUE:
  445.  
  446.     /* modify image data to match visual and colormap
  447.      */
  448.  
  449.     dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
  450.     ximageinfo->depth= ddepth;
  451.     dpixlen= (dbits + 7) / 8;
  452.  
  453.     switch (visual->class) {
  454.     case DirectColor:
  455.     case TrueColor:
  456.       { byte *data, *destptr, *srcptr;
  457.     Pixel pixval, newpixval;
  458.  
  459.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
  460.                       NULL, image->width, image->height,
  461.                       8, 0);
  462.     data= lmalloc(image->width * image->height * dpixlen);
  463.     ximageinfo->ximage->data= (char *)data;
  464.     destptr= data;
  465.     srcptr= image->data;
  466.     switch (image->type) {
  467.     case ITRUE:
  468.       for (y= 0; y < image->height; y++)
  469.         for (x= 0; x < image->width; x++) {
  470.           pixval= memToVal(srcptr, image->pixlen);
  471.           newpixval= redvalue[TRUE_RED(pixval)] |
  472.         greenvalue[TRUE_GREEN(pixval)] | bluevalue[TRUE_BLUE(pixval)];
  473.           valToMem(newpixval, destptr, dpixlen);
  474.           srcptr += image->pixlen;
  475.           destptr += dpixlen;
  476.         }
  477.       break;
  478.     case IRGB:
  479.       for (y= 0; y < image->height; y++)
  480.         for (x= 0; x < image->width; x++) {
  481.           pixval= memToVal(srcptr, image->pixlen);
  482.           pixval= redvalue[image->rgb.red[pixval] >> 8] |
  483.         greenvalue[image->rgb.green[pixval] >> 8] |
  484.           bluevalue[image->rgb.blue[pixval] >> 8];
  485.           valToMem(pixval, destptr, dpixlen);
  486.           srcptr += image->pixlen;
  487.           destptr += dpixlen;
  488.         }
  489.       break;
  490.     default: /* something's broken */
  491.       printf("Unexpected image type for DirectColor/TrueColor visual!\n");
  492.       exit(0);
  493.     }
  494.     ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
  495.                            * i'm talking about */
  496.     break;
  497.       }
  498.     default:
  499.  
  500.       /* only IRGB images make it this far.
  501.        */
  502.  
  503.       /* if our XImage doesn't have modulus 8 bits per pixel, it's unclear
  504.        * how to pack bits so we instead use an XYPixmap image.  this is
  505.        * slower.
  506.        */
  507.  
  508.       if (dbits % 8) {
  509.     byte *data, *destdata, *destptr, *srcptr, mask;
  510.     Pixel pixmask, pixval;
  511.  
  512.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, XYPixmap, 0,
  513.                       NULL, image->width, image->height,
  514.                       8, 0);
  515.  
  516.     data= (byte *)lmalloc(image->width * image->height * dpixlen);
  517.     ximageinfo->ximage->data= (char *)data;
  518.     bzero(data, image->width * image->height * dpixlen);
  519.     ximageinfo->ximage->bitmap_bit_order= MSBFirst;
  520.     ximageinfo->ximage->byte_order= MSBFirst;
  521.     linelen= (image->width + 7) / 8;
  522.     for (a= 0; a < dbits; a++) {
  523.       pixmask= 1 << a;
  524.       destdata= data + ((dbits - a - 1) * image->height * linelen);
  525.       srcptr= image->data;
  526.       for (y= 0; y < image->height; y++) {
  527.         destptr= destdata + (y * linelen);
  528.         *destptr= 0;
  529.         mask= 0x80;
  530.         for (x= 0; x < image->width; x++) {
  531.           pixval= memToVal(srcptr, image->pixlen);
  532.           srcptr += image->pixlen;
  533.           if (index[pixval] & pixmask)
  534.         *destptr |= mask;
  535.           mask >>= 1;
  536.           if (mask == 0) {
  537.         mask= 0x80;
  538.         destptr++;
  539.           }
  540.         }
  541.       }
  542.     }
  543.       }
  544.       else {
  545.     byte *data, *srcptr, *destptr;
  546.  
  547.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
  548.                       NULL, image->width, image->height,
  549.                       8, 0);
  550.  
  551.     dpixlen= (ximageinfo->ximage->bits_per_pixel + 7) / 8;
  552.     data= (byte *)lmalloc(image->width * image->height * dpixlen);
  553.     ximageinfo->ximage->data= (char *)data;
  554.     ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
  555.                            * i'm talking about */
  556.     srcptr= image->data;
  557.     destptr= data;
  558.     for (y= 0; y < image->height; y++)
  559.       for (x= 0; x < image->width; x++) {
  560.         valToMem(index[memToVal(srcptr, image->pixlen)], destptr, dpixlen);
  561.         srcptr += image->pixlen;
  562.         destptr += dpixlen;
  563.       }
  564.       }
  565.       break;
  566.     }
  567.   }
  568.  
  569.   if (verbose)
  570.     printf("done\n");
  571.  
  572.   if (index)
  573.     lfree((byte *)index);
  574.   if (redvalue) {
  575.     lfree((byte *)redvalue);
  576.     lfree((byte *)greenvalue);
  577.     lfree((byte *)bluevalue);
  578.   }
  579.   if (image != orig_image)
  580.     freeImage(image);
  581.   return(ximageinfo);
  582. }
  583.  
  584. /* Given an XImage and a drawable, move a rectangle from the Ximage
  585.  * to the drawable.
  586.  */
  587.  
  588. void sendXImage(ximageinfo, src_x, src_y, dst_x, dst_y, w, h)
  589.      XImageInfo  *ximageinfo;
  590.      int          src_x, src_y, dst_x, dst_y;
  591.      unsigned int w, h;
  592. {
  593.   XGCValues gcv;
  594.  
  595.   /* build and cache the GC
  596.    */
  597.  
  598.   if (!ximageinfo->gc) {
  599.     gcv.function= GXcopy;
  600.     if (ximageinfo->ximage->depth == 1) {
  601.       gcv.foreground= ximageinfo->foreground;
  602.       gcv.background= ximageinfo->background;
  603.       ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
  604.                 GCFunction | GCForeground | GCBackground,
  605.                 &gcv);
  606.     }
  607.     else
  608.       ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
  609.                 GCFunction, &gcv);
  610.   }
  611.   XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
  612.         ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
  613. }
  614.  
  615. /* free up anything cached in the local Ximage structure.
  616.  */
  617.  
  618. void freeXImage(image, ximageinfo)
  619.      Image        *image;
  620.      XImageInfo   *ximageinfo;
  621. {
  622.   if (ximageinfo->gc)
  623.     XFreeGC(ximageinfo->disp, ximageinfo->gc);
  624.   lfree((byte *)ximageinfo->ximage->data);
  625.   ximageinfo->ximage->data= NULL;
  626.   XDestroyImage(ximageinfo->ximage);
  627.   lfree((byte *)ximageinfo);
  628. }
  629.